/**
 * Mecanimso de manejo de eventos para eventos que tienen un nombre global
 *
 * @static
 * @class ElggMap.Event
 */
ElggMap.provide('Event', {
  /**
   * Devuelve la array interna de subscriptores que puede ser directamente
   * manipulada agregando/quitando cosas.
   *
   * @access private
   * @return {Object}
   */
  subscribers: function() {
    // this odd looking logic is to allow instances to lazily have a map of
    // their events. if subscribers were an object literal itself, we would
    // have issues with instances sharing the subscribers when its being used
    // in a mixin style.
    if (!this._subscribersMap) {
      this._subscribersMap = {};
    }
    return this._subscribersMap;
  },

  /**
   * Subscribir a un nombre de evento, invocando una callback cuando se dispara
   * el evento.
   *
   * Por ejemplo, suponiendo que se quiere ser notificado cada vez que la
   * sesión cambia:
   *
   *     ElggMap.Event.subscribe('auth.sessionChange', function(response) {
   *       // Hacer algo con response.session
   *     });
   *
   * Eventos globales:
   *
   * - auth.login -- Se dispara cuando el usuario ingresa. Dispara el servidor
   * - auth.logout -- Se dispara cuando el usuario sale. Dispara el servidor
   * - auth.statusChange -- Se dispara cuando cambia el status de sesión.
   *						 Dispara el servidor
   * - afterinit -- Se dispara cuando termina de ejecutarse .init().
   * - map.built -- Se dispara cuando se termina de armar el mapa base.
   * - map.loaded -- Se dispara cuando se termina de cargar un mapa
   *				 personalizado	desde el servidor sobre el mapa base.
   * - map.edit.started -- Se dispara cuando el mapa entra en modo edición.
   * - map.edit.stopped -- Se dispara cuando el mapa se sale de modo edición.
   * - map.created -- Se dispara cuando se creó un nuevo mapa.
   * - map.saved -- Se dispara cuando se acaba de actualizar 
   *				un mapa en el servidor.
   * - ui.afterinit -- Se dispara cuando se construyó la interfaz gráfica
   *				   al terminar ui.init.
   * - ElggMap.log -- Se dispara el registrar un mensaje en el lgo
   *
   * @access public
   * @param name {String} Nombre del evento.
   * @param cb {Function} La función callback.
   */
  subscribe: function(name, cb) {
    var subs = this.subscribers();

    if (!subs[name]) {
      subs[name] = [cb];
    } else {
      subs[name].push(cb);
    }
  },

  /**
   * Elimina subscripciones a evento, a la inversa de 
   * [ElggMap.Event.subscribe](ElggMap.Event.subscribe).
   *
   * Para sacar un subscriptor, se hace básicamente igual que al agregarlo
   * Se necesita pasar el mismo evento y función para desubscribir que los que
   * fueron utilizados para subscribir. Usando el mismo ejemplo de 
   * [ElggMap.Event.subscribe](ElggMap.event.subscribe), se obtiene:
   *
   *     var onSessionChange = function(response) {
   *       // Hacer algo con response.session
   *     };
   *     ElggMap.Event.subscribe('auth.sessionChange', onSessionChange);
   *
   *     // Después en el código cuando no se quiere ser notificado más.
   *     ElggMap.Event.unsubscribe('auth.sessionChange', onSessionChange);
   *
   * @access public
   * @param name {String} Nombre del evento.
   * @param cb {Function} la función callback.
   */
  unsubscribe: function(name, cb) {
    var subs = this.subscribers()[name];

	$.each(subs, function(key,value) {
      if (value == cb) {
        subs[key] = null;
      }
    });
  },

  /**
   * Escuchar reptediamente un evento a lo largo del tiempo. La callback
   * es invocada inmediatamente cuando se llama a monitor() , y luego, cada
   * vez que el evento se dispara. La subscripción se cancela cuando callback
   * devuelve true.
   *
   * @access private
   * @param {string} name Nombre del evento.
   * @param {function} callback Una función callback. Cualquier argumento
   *				   adicional a monitor se le pasa a callback. Cuando la
   *				   callback devuelve true, el monitoreo termina.
   */
  monitor: function(name, callback) {
    if (!callback()) {
      var
        ctx = this,
        fn = function() {
          if (callback.apply(callback, arguments)) {
            ctx.unsubscribe(name, fn);
          }
        };

      this.subscribe(name, fn);
    }
  },

  /**
   * Elimina todas las subscripciones para un evento.
   *
   * Se necesita el mismo nombre de evento que se pasa a
   * ElggMap.Event.subscribe.
   * Es útil cuando ya no hace falta escuchar el evento y crees que ya colgaste
   * muchos subscriptores.
   *
   * @access private
   * @param name    {String}   nombre del evento
   */
  clear: function(name) {
    delete this.subscribers()[name];
  },

  /**
   * Dispara un evento. El primer argumento es el nombre, el resto de los
   * argumentos, se pasan a los subscriptores.
   *
   * @access private
   * @param name {String} el nombre del evento
   */
  fire: function() {
    var
      args = Array.prototype.slice.call(arguments),
      name = args.shift(),
	  subscribers = this.subscribers();
	ElggMap.log('Event fired: ' + name);
	subscribers = subscribers[name] ? subscribers[name] : []; 
    $.each(subscribers, function(key,sub) {
      // this is because we sometimes null out unsubscribed rather than jiggle
      // the array
      if (sub) {
        sub.apply(this, args);
      }
    });
  }
});